2

I'm having some problems. How we can define a function outside of a function that can be used in a class property? Also, how we can insert the self parameter into the function signature? I would like to visualize it like this:

>>> def a(self, x):   #I thought maybe class will give "self" to this property function
...     print(self)
... 
>>> class aa:
...     def __init__(self):
...         pass
...     @a
...     def p():
...         print('in it')
... 
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 4, in aa
    TypeError: a() missing 1 required positional argument: 'x'

I want to define a function outside but to use inside of a class. Like a class's method as a property. How can I do this?

gmds
  • 19,325
  • 4
  • 32
  • 58
Günel Resulova
  • 151
  • 1
  • 10
  • I'm not sure I understand what you're asking for. Do you want to actually use `property` to call the `a` function whenever some attribute of an instance of `aa` get accessed? Or are you just using `property` as an example of a decorator that often gets applied with `@property`? Because you can do either of those things, if you understand which you want. You can also just copy a function defined outside of a class into the class and use it as a regular method (with no decorators or properties involved)! – Blckknght Apr 06 '19 at 21:24
  • Does this help?: https://docs.python.org/3.7/howto/descriptor.html – thebjorn Apr 06 '19 at 21:26
  • first of it.I want to get class's atributes – Günel Resulova Apr 06 '19 at 21:27

2 Answers2

3

It's not really clear what you want your out-of-class function to do. There are a bunch of possibilities, but you may not know the terminology yet to describe it to us.

Here's the three I think are most likely:

  1. You may want your function to be a decorator. That means you can apply it to a method with @decorator syntax to other functions, including methods in a class.

    For this to work, your function needs to be written to accept a function object as its only argument. Whatever it returns is what will replace the function or method it was being called on, so usually you want to return a callable, but you could instead return a descriptor like property does. Try something like this:

    def decorator(func):
        def wrapper(self, *args, **kwargs):
            print("in the wrapper")
            result = func(self, *args, **kwargs)
            print("wrapper is done")
            return result
        return wrapper
    
    class Foo:
        @decorator
        def foo(self, x):
            print("in foo(), x is", x)
    
    f = Foo()
    f.foo(1) # prints three messages
    

    When you call the foo method, you're actually going to be calling the wrapper method that the decorator returned after it was applied to the original method (func). Because of how we wrote the wrapper, it will call func so the original method prints out its message too.

  2. You may want to use property (a descriptor type) to call your out-of-class function. This is a less common way of using property than applying it as a decorator on a method, but it's not impossible. You could even have two different functions, one to be called when requesting the attribute, the other than will be called when setting it (but I'll demonstrate with just the getter):

    def getter(obj):
        print("in the getter")
        return 1
    
    class Foo2:
        foo = property(getter)
    
    f2 = Foo2()
    print(f2.foo) # prints a message from the getter function first, then prints 1
    

    Note that you can't use @decorator syntax when building a property this way. That is only legal syntax immediately before a function definition, and we're not defining any functions that way inside our class.

  3. You may just want to copy a function defined outside of the class into it, without any decorator or property nonsense. This is the easiest one to do, it's just a simple assignment:

    def func(self, x):
        print("x is", x)
    
    class Foo3:
        method = func  # just assign the global to a name in the class body
        func = func    # you can even use the same name if you don't mind confusing people
    
    f3 = Foo3()
    f3.method(1)
    f3.func(2)
    
Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • For the first case, how is self passed to wrapper function? Isn't it passed when method is called via object like `obj.func()`? Is it because as you said the wrapper function replaces the original function? – Dhruv Apr 06 '23 at 07:58
1

If you want to create a property that uses a function defined outside your class, it would be something like this:

def myfunc(self):
    return self._p

class Foo:
    def __init__(self, p):
        self._p = p
    p = property(myfunc)

f = Foo("Alpha")
f.p # gives "Alpha"

property accepts a function as its (first) argument. The function should have self as a parameter, and should return the value that you want the property to evaluate to.

khelwood
  • 55,782
  • 14
  • 81
  • 108
  • property created.but when im trying to use it like @p , it gives property is not callable.. – Günel Resulova Apr 06 '19 at 21:35
  • 1
    @Günel Why are you putting `@p` ? – khelwood Apr 06 '19 at 21:36
  • essentiallyproblem is that i want to define a function outside and i want to use it in class as property that "will take a method(function in class)" and will return anything.And in this function I also want to work with self. – Günel Resulova Apr 06 '19 at 21:43
  • 1
    You're using the word property to mean something other than a property, and that is very unclear. – khelwood Apr 06 '19 at 21:44
  • yes I said already.Maybe not property, but like property .I will use this with "@" statement..Will take a method of class and self....is clear mr? – Günel Resulova Apr 06 '19 at 21:46
  • I don't know what you are trying to accomplish. I am not convinced that you know either. – khelwood Apr 06 '19 at 21:48