omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Getting the parent of a dynamically method as a function

    Pythonista
    attr dynamically parent
    6
    61
    43196
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Oscar
      Oscar last edited by

      @Phuket2, I don't know why you want to do this, I'm not sure I even know what you want to do.

      Perhaps something like this?

      import ui
      
      def extra_function(self, message):
        print 'My class: ', self.__class__
        print message
      
      b = ui.Button()
      b.extra_function = lambda *a, **kw: extra_function(b, *a, **kw)
      
      b.extra_function('The message')
      
      1 Reply Last reply Reply Quote 1
      • Olaf
        Olaf last edited by Olaf

        @Phuket2, is my understanding correct that originally your intent was to modify the class, only to get can't set attributes of built-in/extension type '_ui.Button'?
        Going one way, i.e. to make a derived class, is a dead end, yielding Error when calling the metaclass bases, type '_ui.Button' is not an acceptable base type. Going the other way, modifying a class object, helps as your example shows.
        However, I don't think an attribute can find out the object it belongs to, as you try to achieve. Though inspect can find the caller, that is the calling function, i.e. one "up" the stack, __main__ in your example, not the "calling" (actually containing) object.
        Sorry I can't be of more help, but I think this isn't feasible along this route.

        1 Reply Last reply Reply Quote 0
        • Olaf
          Olaf last edited by

          On 2nd thought, if the reason you want your function to know the button is to be "self-aware" when being pressed, you may want to look to method action, which gets a singlesender argument doing just that

          Phuket2 2 Replies Last reply Reply Quote 0
          • Phuket2
            Phuket2 last edited by

            Sorry guys, appears I was not clear. But the code I posted works. But in the test_func, I want to be able to access the object that called the function.
            I can pass a direct reference as below... But this is not good..

            
            import ui
            
            def test_func(obj, msg):
            	'''
            	i would like to get a reference to the caller here
            	being the btn. 
            	i am pretty sure the answer lies with the inspect module,
            	but i cant figure it out.
            	MAYBE, its even easier than that... well that would be great
            	'''
            	print msg
            	print obj.title
            
            btn = ui.Button(title = 'help')
            btn.msg = test_func
            btn.msg(btn, 'I am on to something...')
            

            So in test_func, I would like to get access to ui object that called it.

            1 Reply Last reply Reply Quote 0
            • Phuket2
              Phuket2 @Olaf last edited by

              @Olaf , not about actions. With this mechanism can extend ui elements eg ui.button , ui.TextField etc with your own methods/function dynamically. It can still be done, but if you need to access the object your are called from you are up the creek unless you explicitly pass the obj each time.

              1 Reply Last reply Reply Quote 0
              • Phuket2
                Phuket2 @Olaf last edited by

                @Olaf , are you on 1.6 or 1.5? Both code samples I posted in this thread work.

                1 Reply Last reply Reply Quote 0
                • Oscar
                  Oscar last edited by

                  @Phuket2 Did you see my reply above? Isn't that exactly what you are asking for? Why not? You have the reference to the button in the method without giving it as an argument every time you call it.

                  Phuket2 1 Reply Last reply Reply Quote 1
                  • Phuket2
                    Phuket2 @Oscar last edited by

                    @Oscar , YES.....Exactly what I wanted. Sorry the syntax is not very clear to me. lambda etc... it Threw me off. But I did a few tests with your solution and worked perfectly. Late here now. But I will implement tomorrow. I am adding these funcs at runtime based on dicts. Not that difficult, I just want to get my head around your code. Easy for you, not for me 😱😬
                    But that little bit of code is powerful and opens up a lot in my mind.
                    One question, as stupid as it maybe, is it possible to express the same without the use of the Lambda?

                    1 Reply Last reply Reply Quote 0
                    • mikael
                      mikael last edited by

                      Other ways to bind a new method to an object instance (class not affected):

                      1. Using types, really binding:
                      import types
                      btn.msg = types.MethodType(test_func, btn)
                      
                      1. Using functools, just add the object to be always included as the first argument (like the lambda):
                      from functools import partial
                      btn.msg = partial(test_func, btn)
                      
                      Phuket2 1 Reply Last reply Reply Quote 1
                      • Oscar
                        Oscar last edited by

                        @mikael beat me to it.. I was going to suggest partial if you prefer to not use lambda: https://docs.python.org/2/library/functools.html#functools.partial

                        1 Reply Last reply Reply Quote 0
                        • Phuket2
                          Phuket2 last edited by

                          Thanks everyone here for all the excellent feedback and help. Will have a go with types now. Looks straight fwd enough

                          1 Reply Last reply Reply Quote 0
                          • Phuket2
                            Phuket2 @mikael last edited by

                            @mikael , I was stumped there for a few mins because I am adding the extra functions from a dict. Where the k is method name and v is function/method (address).

                            But I did the below. It works. But not really understanding this well enough, just wanted to ask as you guys if this is seen as an acceptable way call it. As I say, it works great. Just want to be sure I haven't overlooked something

                            Thanks

                            	for k,v in _extended_methods.iteritems():
                            		setattr(ctl, k, types.MethodType(v, ctl))
                            		#ctl. = types.MethodType(v, ctl)
                            	
                            
                            1 Reply Last reply Reply Quote 0
                            • mikael
                              mikael last edited by

                              Coming back to this...

                              Here is how I add functionality to built-in ui classes these days, using ProxyTypes.

                              import ui
                              from proxy import ObjectWrapper
                              
                              class ButtonWrapper(ObjectWrapper):
                              	def __init__(self, obj):
                              		ObjectWrapper.__init__(self, obj)
                              	def msg(self, leader):
                              		print leader + ': ' + self.name
                              		
                              button = ButtonWrapper(ui.Button(name = 'Wrapped ui.Button'))
                              
                              button.msg('Calling extra method')
                              
                              Phuket2 1 Reply Last reply Reply Quote 2
                              • Phuket2
                                Phuket2 @mikael last edited by

                                @mikael said:

                                Coming back to this...

                                Here is how I add functionality to built-in ui classes these days, using ProxyTypes.

                                import ui
                                from proxy import ObjectWrapper

                                class ButtonWrapper(ObjectWrapper):
                                def init(self, obj):
                                ObjectWrapper.init(self, obj)
                                def msg(self, leader):
                                print leader + ': ' + self.name

                                button = ButtonWrapper(ui.Button(name = 'Wrapped ui.Button'))

                                button.msg('Calling extra method')

                                @mikael, sorry just revisiting this. But is above complete? I just mean button is no longer considered a ui.View.
                                Sorry, I have a idea, I am just totally missing the point here

                                1 Reply Last reply Reply Quote 0
                                • mikael
                                  mikael last edited by

                                  I am heavily utilizing this in my current project, so I can confirm that it works. The only gotcha I have found is that you have to give proxy_view.__subject__ instead of just the proxy_view to add_subview since, as you say, proxy_view is not descended from View. And likewise for ObjCInstance, if you are using objc_util.

                                  1 Reply Last reply Reply Quote 0
                                  • mikael
                                    mikael last edited by

                                    @Phuket2, that said, I think I understand what you are aiming for in your recent discussions, and agree that we are not there yet. Let me get back to this.

                                    Phuket2 1 Reply Last reply Reply Quote 0
                                    • Phuket2
                                      Phuket2 @mikael last edited by

                                      @mikael , ok. Sorry been a while since I looked at this. I just thought there was some magic happening that I was not getting

                                      1 Reply Last reply Reply Quote 0
                                      • mikael
                                        mikael last edited by

                                        So, I think that one of the things we want is the ability to style UI components with inheritance. This is relatively straightforward and clean with the proxy approach:

                                        # coding: utf-8
                                        import ui
                                        from proxy import ObjectWrapper
                                        
                                        class DefaultStyle(ObjectWrapper):
                                        	def __init__(self, obj):
                                        		ObjectWrapper.__init__(self, obj)
                                        		self.background_color = '#fff7ee'
                                        		self.tint_color = 'black'
                                        	
                                        class HighlightStyle(DefaultStyle):
                                        	def __init__(self, obj):
                                        		DefaultStyle.__init__(self, obj)
                                        		self.tint_color = 'red'
                                        		
                                        button = HighlightStyle(ui.Button())
                                        button.title = 'Styled button'
                                        button.present()
                                        
                                        Phuket2 1 Reply Last reply Reply Quote 0
                                        • Phuket2
                                          Phuket2 @mikael last edited by

                                          @mikael , hmmm. I am having a bad day today. Nothing is working 😱
                                          You can see below I have to
                                          from peak.util.proxies import ObjectWrapper
                                          I can't
                                          from proxy import ObjectWrapper

                                          But I am getting a no module named 'pkg_resources' error. Are you on v2 beta?
                                          Could be something with the beta

                                          # coding: utf-8
                                          import ui
                                          #from proxy import ObjectWrapper
                                          
                                          from peak.util.proxies import ObjectWrapper
                                          
                                          class DefaultStyle(ObjectWrapper):
                                          	def __init__(self, obj):
                                          		ObjectWrapper.__init__(self, obj)
                                          		self.background_color = '#fff7ee'
                                          		self.tint_color = 'black'
                                          
                                          class HighlightStyle(DefaultStyle):
                                          	def __init__(self, obj):
                                          		DefaultStyle.__init__(self, obj)
                                          		self.tint_color = 'red'
                                          
                                          button = HighlightStyle(ui.Button())
                                          button.title = 'Styled button'
                                          button.present()
                                          
                                          1 Reply Last reply Reply Quote 0
                                          • mikael
                                            mikael last edited by

                                            Sorry, I have the proxies code in a different place, but it is the same code. And yes, I am on v2 beta.

                                            Phuket2 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors