Git Product home page Git Product logo

Comments (8)

bslatkin avatar bslatkin commented on September 13, 2024 1

@dec1 Can you show me an example in code that matches your expectations? The result of __getattr__ is cached in the __dict__ of the object, whereas __getattribute__ is never cached. See this part of the documentation. Please reopen if you have a more clear example. Thanks!

from effectivepython.

dec1 avatar dec1 commented on September 13, 2024
class MyClass(object):
    def __init__(self):
        self.exists = 5

    def __getattr__(self, name):
        print('Called __getattr__(%s)' % name)
        value = 'Value for %s' % name
        #setattr(self, name, value)
        return value

data = MyClass()
for i in range(1,5):
    print("(", i, ")")
    data.foo
( 1 )
Called __getattr__(foo)
( 2 )
Called __getattr__(foo)
( 3 )
Called __getattr__(foo)
( 4 )
Called __getattr__(foo)

__getattr__ gets called every time that data.foo is accessed

from effectivepython.

dec1 avatar dec1 commented on September 13, 2024

tested with python 3.6.1

from effectivepython.

bslatkin avatar bslatkin commented on September 13, 2024

Thanks for the working example, that makes it more clear where the confusion is.

The text from Item 32 is:

Understand that __getattr__ only gets called once when accessing a missing attribute, whereas __getattribute__ gets called every time an attribute is accessed.

The key word here is missing. In your example, you even have the line # setattr(self, name, value) that demonstrates the difference. Once you setattr for the attribute name, then __getattr__ will not get called again.

Here's a modification to your example that shows the difference:

class MyClass(object):
    def __init__(self):
        self.exists = 5

    def __getattr__(self, name):
        print('Called __getattr__(%s)' % name)
        value = 'Value for %s' % name
        setattr(self, name, value)
        return value

    def __getattribute__(self, name):
        print('Called __getattribute__(%s)' % name)
        return object.__getattribute__(self, name)

data = MyClass()
for i in range(1, 5):
    print("(%d)" % i)
    data.foo

Output:

(1)
Called __getattribute__(foo)
Called __getattr__(foo)
(2)
Called __getattribute__(foo)
(3)
Called __getattribute__(foo)
(4)
Called __getattribute__(foo)

from effectivepython.

dec1 avatar dec1 commented on September 13, 2024

The statement

... getattr only gets called once when accessing a missing attribute, ....

is clearly wrong or at least very misleading.

A correct (general) statement would be

.. getattr only gets called when (every time) a missing attribute is accessed, ....

In the special case where you create the attribute after the first access (eg in the function __getattr__ itself) then __getattr__ will not be called again, because it's then no longer missing.
You could just as well create the attribute the second time __getattr__ gets called and say

... getattr only gets called twice when accessing a missing attribute, ....

This would be equally wrong/misleading.

from effectivepython.

bslatkin avatar bslatkin commented on September 13, 2024

I see your point there. The "special case" is the most common case I've seen. But I agree that I'm assuming something implicitly about the way __getattr__ is used in practice (where its definition usually calls setattr).

I think it would be more clear to update the suggestion text to this:

Understand that getattr only gets called when accessing a missing attribute, whereas getattribute gets called every time any attribute is accessed.

from effectivepython.

dec1 avatar dec1 commented on September 13, 2024

Yes, this would be a good and sufficient change.
Best Wishes, Declan

from effectivepython.

bslatkin avatar bslatkin commented on September 13, 2024

This will be resolved in a future release. Thanks

from effectivepython.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.